//多态的学习测试类

/**
 * 去完成某个行为，当不同的对象去完成的时候会产生出不同的状态
 * 同一件事情，发生在不同对象的身上，就会产生不同的结果
 */
//public class Test {
//    public static void main(String[] args) {
//        //向上转型
////        Dog dog = new Dog("小狗",5);
////        Animal animal = dog;
//        //上述两行代码也可以写成
//        Animal animal = new Dog("小狗", 10);
//    }
//}


//向上转型
//实际就是创建一个子类对象，将其当成父类对象来使用
//有三种方式可以发生向上转型
//1.直接赋值(即上面的10 - 13 代码实现)
//2.方法传参的方式(即21 - 29 代码实现)
//3.方法返回值的方式(即35 - 42代码实现)

//public class Test {
//    public static void main(String[] args) {
//        Dog dog = new Dog("小狗", 10);
//        fun1(dog);
//    }
//    public static void fun1(Animal animal){
//
//    }
//}

//public class Test {
//    public static void main(String[] args) {
//        Animal animal = fun2();
//    }
//    public static Animal fun2(){
//        return new Dog("小狗",10);
//    }
//}


/**
 * 重写(override):也成为覆盖。
 * 重写是值子类对父类的非静态，非private，非final修饰，非构造方法等的实现过程的重新编写
 * 返回值和形参都不能改变，即外壳不变，核心重写。重写的好处在于可以根据子类的需要，定义特定的自己的行为
 *
 */

//eat的重写
//public class Test {
//    public static void main(String[] args) {
//        Animal animal = new Dog("小狗", 5);
//        animal.eat();
//    }
//}

/**
 * 重写：
 * 1.方法名必须相同
 * 2.参数列表必须相同(类型，个数，顺序)
 * 3.返回值必须相同--
 */
/**
 * 重写的过程
 * 1.向上转型 55 行代码实现
 * 2.通过父类引用，调用这个父类和子类重写的方法
 * 结果：
 * 56行代码调用了子类Dog中的方法！！！
 * 这个过程，叫做运行时绑定 或者 动态绑定
 *
 * 还有一个过程是静态绑定/编译时绑定：方法的重载
 * 在编译的时候，通过方法的参数，也就是说在编译的时候就能确定使用的是那个方法
 * 但是运行时绑定在编译时看不出来，只能在运行的时候绑定
 * 使用javap命令反汇编该字节码文件,得到如下图所示字节码指令内容
 * javap -c
 */


/**
 * 重写的注意事项：
 * 1.被private static final修饰的方法不能进行重写
 * 有些书上讲被final修饰过的方法 叫做密封方法
 * 2.访问修饰限定符
 * 子类的访问修饰限定符的范围一定要大于等于父类的访问修饰限定符的范围
 * 3.重写的方法，可以用@Override 注解来显示指定 帮我们进行合法性校验
 * 例如，一不小心讲方法名字拼写错了，编译器就会发现父类中没有该方法，就会编译报错，提示无法构成重写
 */


/**
 * 重写和重载的区别
 * 参数列表：重写 一定不能修改 但是重载必须得修改
 * 返回类型：冲写一定不能修改(除非可以构成父子类的关系)  但是重载是可以修改的
 * 访问限定符：重写的子类的访问修饰限定符的范围必须大于等于父类的访问修饰限定符 重载的访问修饰限定符可以修改
 *
 * 方法的重载 是一个类的多态性表现
 * 重写：是子类和父类的之间的一种多态性表现
 */

//静态绑定：也称为前期绑定(早绑定)，即在编译时，根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
//动态绑定：也称为后期绑定(晚绑定)，即在编译时，不能确定方法的行为，需要等到程序运行时，才能够确定具体调用那个类的方法。



//向下转型
//public class Test {
//    public static void main(String[] args) {
//        Animal animal2 = new Bird("小鸟", 10);
////        animal2.fly;//err
//
//        //向下转型
//        Bird bird = (Bird)animal2;
//        bird.fly();
//        bird.eat();

//        Animal animal1 = new Dog("小狗",6);
//        Bird bird2 = (Bird)animal1;
//        bird2.fly();//err  ----  ClassCastException
//
//        Animal animal1 = new Dog("小狗", 6);
//        if (animal1 instanceof Bird){
//            Bird bird2 = (Bird)animal1;
//            bird2.fly();
//        } else {
//            System.out.println(animal1.name + "不是鸟，飞不了");
//        }
//    }
//}

//public class Test {
//    public static void main(String[] args) {
//        Animal animal = new Bird("zzr", 5);
//        animal.fly();
//    }
//}


//避免在构造方法中调用重写的方法
class B {
    public B (){
        fun();
    }
    public void fun(){
        System.out.println("B");
    }
}
class D extends B {
    public int num = 1;
    @Override
    public void fun() {
        System.out.println("D " + "num = " + num);
    }
}
public class Test {
    public static void main(String[] args) {
        D d = new D();
        //如果在构造方法实现重写的话，会执行子类
        //注意num是默认值0；
        //因为它在打印num的时候并没有把父类执行完，也就是说没有进入子类的num = 1的这行代码
    }
}

